use std::string::String;

use actix_web::Result;
use base64::{engine::general_purpose::STANDARD, Engine as _};
use chrono::{SubsecRound, Utc};
use jsonwebtoken::{decode, DecodingKey, Validation};
use sea_orm::{ActiveValue::Set, DatabaseTransaction, TryIntoModel};
use serde_json::Value;

use attestation_common::log::{error, info, warn};
use crate::entities::{
    policy::Policy,
    policy_db_model::{ActiveModel, Model},
    signature_policy::SignaturePolicy,
};
use crate::policy_error::policy_error::PolicyError;
use crate::repositories::policy_repository::PolicyRepository;
use crate::util::policy_util::PolicyUtil;
use key_management::api::{
    crypto_operations::CryptoOperations,
    impls::default_crypto_impl::DefaultCryptoImpl,
    SignResponse,
};


pub struct PolicyHandler;

impl PolicyHandler {

    const SIGNATURE_KEY_TYPE: &'static str = "FSK";

    fn decode_policy_content(content: String, content_type: &str) -> Result<String, PolicyError> {
        let check_content_size = |decoded_content: &str| {
            let max_size_kb = PolicyUtil::get_u64_yaml_config("attestation_service.policy.policy_content_size_limit", 500) as usize;
            info!("{:?}", decoded_content.len());
            if decoded_content.len() > max_size_kb * 1024 {
                return Err(PolicyError::PolicyContentSizeLimitReached(format!("Policy content size exceeds {} KB limit", max_size_kb)));
            }
            Ok(decoded_content.to_string())
        };

        if content_type == "text" {
            STANDARD.decode(&content)
                .map(|bytes| String::from_utf8_lossy(&bytes).into_owned())
                .map_err(|_| PolicyError::IncorrectFormatError("Failed to decode base64 content".to_string()))
                .and_then(|decoded| check_content_size(&decoded))
        } else if content_type == "jwt" {
            let parts: Vec<&str> = content.split('.').collect();
            if parts.len() != 3 {
                return Err(PolicyError::IncorrectFormatError("Invalid JWT format".to_string()));
            }

            let header = STANDARD.decode(parts[0])
                .map_err(|_| PolicyError::IncorrectFormatError("Failed to decode JWT header".to_string()))
                .and_then(|bytes| String::from_utf8(bytes)
                    .map_err(|_| PolicyError::IncorrectFormatError("JWT header is not valid UTF-8".to_string()))
                )?;
            
            let header_json: Value = serde_json::from_str(&header)
                .map_err(|_| PolicyError::IncorrectFormatError("JWT header is not valid JSON".to_string()))?;
            
            let alg = header_json.get("alg")
                .and_then(|v| v.as_str())
                .ok_or_else(|| PolicyError::IncorrectFormatError("JWT header missing 'alg' field".to_string()))?;

            let mut validation = Validation::new(alg.parse().map_err(|_| PolicyError::IncorrectFormatError("Invalid algorithm".to_string()))?);
            validation.validate_exp = false;
            validation.validate_nbf = false;
            validation.required_spec_claims.clear();
            let token_data = decode::<Value>(
                &content,
                &DecodingKey::from_secret(b""),
                &validation
            ).map(|token| token.claims)
            .map_err(|e| PolicyError::IncorrectFormatError(format!("Failed to decode JWT token: {}", e)))?;

            let decoded_content = token_data
                .get("policy")
                .and_then(|v| v.as_str())
                .map(|policy| {
                    STANDARD.decode(policy)
                        .map(|bytes| String::from_utf8_lossy(&bytes).into_owned())
                        .map_err(|_| PolicyError::IncorrectFormatError("Failed to decode policy content in JWT".to_string()))
                })
                .transpose()?
                .unwrap_or(content);
            
            check_content_size(&decoded_content)
        } else {
            Err(PolicyError::IncorrectFormatError("Unsupported content type".to_string()))
        }
    }

    pub async fn create_policy(
        headers: &actix_web::http::header::HeaderMap,
        request_body: &serde_json::Value,
        db: &DatabaseTransaction,
    ) -> Result<Policy, PolicyError> {
        let user_id = headers
            .get("user_id")
            .and_then(|h| h.to_str().ok())
            .unwrap_or("system")
            .to_string();

        let policy_count = PolicyRepository::get_user_policy_count(db, user_id.clone()).await?;
        let policy_limit = PolicyUtil::get_u64_yaml_config("attestation_service.policy.single_user_policy_limit", 30);
        if policy_count >= policy_limit {
            error!("User {:?} has reached the maximum number of policies: {:?}.", user_id, policy_limit);
            return Err(PolicyError::PolicyLimitReached("User has reached the maximum number of policies.".to_string()));
        }
        
        let name = request_body["name"].as_str().unwrap().to_string();
        let content_type = request_body["content_type"].as_str().unwrap().to_string();
        let content = request_body["content"].as_str().unwrap().to_string();
        let content = Self::decode_policy_content(content, &content_type)?;
        let description = request_body
            .get("description")
            .and_then(|v| v.as_str())
            .unwrap_or("")
            .to_string();

        let attester_type = request_body["attester_type"]
            .as_array()
            .unwrap()
            .iter()
            .map(|v| v.as_str().unwrap().to_string())
            .collect();
        let is_default = request_body
            .get("is_default")
            .and_then(|v| v.as_bool())
            .unwrap_or(false);
    
        let policy = Policy::new(name, description, content, attester_type, Some(is_default));
        
        Ok(policy)
    }

    pub fn create_policy_model(
        headers: &actix_web::http::header::HeaderMap,
        policy: &Policy
    ) -> ActiveModel {
        let user_id = headers
            .get("user_id")
            .and_then(|h| h.to_str().ok())
            .unwrap_or("system")
            .to_string();

        let mut policy_model: ActiveModel = policy.clone().into();
        policy_model.signature = sea_orm::Set(Vec::new());
        policy_model.key_version = sea_orm::Set(String::new());
        policy_model.valid_code = sea_orm::Set(0); // 入库时默认为0
        policy_model.user_id = sea_orm::Set(user_id);
        policy_model.product_name = sea_orm::Set(String::new());
        policy_model.product_type = sea_orm::Set(String::new());
        policy_model.board_type = sea_orm::Set(String::new());
    
        policy_model
    }

    pub async fn build_update_model(
        request_body: &serde_json::Value,
        db: &sea_orm::DatabaseTransaction,
        policy: &Model,
    ) -> Result<ActiveModel, PolicyError> {
        let mut model = ActiveModel::default();
        macro_rules! update_field {
            ($field:ident, $body_key:expr, $type:ty) => {
                model.$field = match request_body.get($body_key) {
                    Some(value) if !value.is_null() => {
                        if let Some(str_value) = value.as_str() {
                            Set(str_value.to_string())
                        } else {
                            Set(policy.$field.clone())
                        }
                    },
                    _ => Set(policy.$field.clone())
                };
            };
            ($field:ident, $body_key:expr, $type:ty, $convert:expr) => {
                model.$field = match request_body.get($body_key) {
                    Some(value) if !value.is_null() => {
                        if let Some(arr) = value.as_array() {
                            let converted = arr
                                .iter()
                                .filter_map($convert)
                                .collect::<Vec<_>>();
                            Set(serde_json::to_value(converted)
                                .map_err(|e| PolicyError::IncorrectFormatError(e.to_string()))?)
                        } else {
                            Set(policy.$field.clone())
                        }
                    },
                    _ => Set(policy.$field.clone())
                };
            };
        }

        update_field!(policy_id, "id", str);
        update_field!(policy_name, "name", str);
        update_field!(policy_description, "description", str);
        update_field!(attester_type, "attester_type", array, |v| v.as_str().map(String::from));
        model.policy_content = if let Some(content) = request_body.get("content").and_then(|v| v.as_str()) {
            let content_type = request_body.get("content_type")
                .and_then(|v| v.as_str())
                .ok_or_else(|| PolicyError::IncorrectFormatError("content_type is required when content is provided".to_string()))?;
            Set(Self::decode_policy_content(content.to_string(), content_type)?)
        } else {
            Set(policy.policy_content.clone())
        };
        model.is_default = Set(request_body
            .get("is_default")
            .and_then(|v| v.as_bool())
            .unwrap_or(policy.is_default));
        model.update_time = Set(Utc::now().trunc_subsecs(0));
        let current_version =
            PolicyRepository::get_policy_version(db, model.policy_id.clone().unwrap()).await?;
        model.policy_version = Set((current_version + 1).try_into().unwrap());
        model.create_time = Set(policy.create_time);
        model.user_id = Set(policy.user_id.clone());
        model.signature = Set(policy.signature.clone());
        model.valid_code = Set(policy.valid_code);
        model.key_version = Set(policy.key_version.clone());
        model.product_name = sea_orm::Set(String::new());
        model.product_type = sea_orm::Set(String::new());
        model.board_type = sea_orm::Set(String::new());

        Ok(model)
    }


    pub async fn verify_and_sign_policy(
        db: &DatabaseTransaction,
        policy: &Model,
        update_model: ActiveModel,
    ) -> Result<ActiveModel, PolicyError> {
        let is_require_sign = PolicyUtil::get_bool_yaml_config("attestation_service.attestation_verifier.is_require_sign", false);
        if !is_require_sign {
            return Ok(update_model);
        }

        let signature_policy = SignaturePolicy::from(policy.clone());
        match Self::verify_policy_signature(db, &signature_policy).await {
            Ok(true) => {
                // TODO: Get the sample output corresponding to the policy update plugin, match the sample output, and return failure (400) directly if there is a syntax error
                match Self::sign_policy(update_model).await {
                    Ok(model) => Ok(model),
                    Err(e) => {
                        error!("Failed to sign updated policy: {:?}", e);
                        Err(e)
                    }
                }
            }
            Ok(false) => {
                error!("Policy signature verification failed!");
                Err(PolicyError::PolicySignatureFailure("Policy signature verification failed".to_string()))
            }
            Err(e) => {
                error!("Policy signature verification failed: {:?}", e);
                Err(e)
            }
        }
    }

    pub async fn sign_policy(mut policy_model: ActiveModel) -> Result<ActiveModel, PolicyError> {
        info!("Start to sign policy!");
        let policy_sign_model: SignaturePolicy = policy_model.clone().try_into_model().unwrap().into();
        let data = policy_sign_model.encode_to_bytes();
        let crypto_ops = DefaultCryptoImpl;
        match crypto_ops.sign(&data, Self::SIGNATURE_KEY_TYPE).await {
            Ok(SignResponse { signature, key_version }) => {
                policy_model.signature = Set(signature);
                policy_model.key_version = Set(key_version);
                info!("Sign policy success!");
                Ok(policy_model)
            }
            Err(e) => {
                error!("Failed to sign policy: {:?}", e);
                Err(PolicyError::PolicySignatureFailure(e.to_string()))
            }
        }
    }

    pub async fn get_all_policies(
        db: &sea_orm::DatabaseTransaction,
        user_id: String,
    ) -> Result<Vec<Policy>, PolicyError> {
        info!("Query all user policy!");
        let sign_policies = PolicyRepository::get_all_policies(db, user_id).await?;
        let is_require_sign = PolicyUtil::get_bool_yaml_config("attestation_service.attestation_verifier.is_require_sign", false);
        let mut verify_policies = sign_policies;
        if is_require_sign {
            verify_policies = Self::verify_policies_signature(verify_policies, db).await?;
        }
        let policies: Vec<Policy> = verify_policies
            .into_iter()
            .map(|sp| sp.into())
            .collect();

        Ok(policies)
    }

    pub async fn query_policies_by_ids(
        db: &sea_orm::DatabaseTransaction,
        request_body: &serde_json::Value,
        user_id: String,
    ) -> Result<Vec<Policy>, PolicyError> {
        info!("Query policy by ids!");
        let policy_ids: Vec<String> = request_body["ids"]
            .as_str()
            .map(|s| s.split(','))
            .unwrap_or_else(|| "".split(','))  
            .map(|id| id.trim().to_string())  // 直接保留字符串格式
            .filter(|id_str| !id_str.is_empty())  // 仅过滤空字符串
            .collect();
        let sign_policies = PolicyRepository::get_policies_by_ids(db, policy_ids, user_id).await?;
        
        let is_require_sign = PolicyUtil::get_bool_yaml_config("attestation_service.attestation_verifier.is_require_sign", false);
        let mut verify_policies = sign_policies;
        if is_require_sign {
            verify_policies = Self::verify_policies_signature(verify_policies, db).await?;
        }

        let policies: Vec<Policy> = verify_policies
            .into_iter()
            .map(|sp| sp.into())
            .collect();

        Ok(policies)
    }

    pub async fn query_policies_by_type(
        db: &sea_orm::DatabaseTransaction,
        request_body: &serde_json::Value,
        user_id: String,
    ) -> Result<Vec<Policy>, PolicyError> {
        info!("Query policy by attester_type!");
        let attester_type = request_body["attester_type"]
            .as_str()
            .map(|s| s.trim())
            .ok_or_else(|| PolicyError::IncorrectFormatError("attester_type must be a string".to_string()))?;
        let sign_policies = PolicyRepository::get_policies_by_type(db, attester_type.to_string(), user_id).await?;
        let is_require_sign = PolicyUtil::get_bool_yaml_config("sign.is_require_sign", false);
        let mut verify_policies = sign_policies;
        if is_require_sign {
            verify_policies = Self::verify_policies_signature(verify_policies, db).await?;
        }
        let policies: Vec<Policy> = verify_policies
            .into_iter()
            .map(|sp| sp.into())
            .collect();

        Ok(policies)
    }

    async fn verify_policies_signature(
        sign_policies: Vec<SignaturePolicy>,
        db: &sea_orm::DatabaseTransaction,
    ) -> Result<Vec<SignaturePolicy>, PolicyError> {
        let crypto_impl = DefaultCryptoImpl;
        let mut verify_policies = Vec::new();

        for mut sign_policy in sign_policies {
            if sign_policy.valid_code == 0 {
                let data = sign_policy.encode_to_bytes();
                match crypto_impl
                    .verify(Self::SIGNATURE_KEY_TYPE, Some(&sign_policy.key_version), data, sign_policy.signature.clone())
                    .await
                {
                    Ok(true) => {
                        verify_policies.push(sign_policy);
                    }
                    Ok(false) => {
                        PolicyRepository::set_is_corrupted(db, sign_policy.policy_id.clone()).await?;
                        sign_policy.valid_code = 1;
                        verify_policies.push(sign_policy);
                        
                    }
                    Err(e) => {
                        error!("Failed to verify policy signature: {:?}", e);
                        return Err(PolicyError::DatabasePolicySignatureError(e.to_string()));
                    }
                }
            } else {
                verify_policies.push(sign_policy);
            }
            
        }
        
        Ok(verify_policies)
    }

    pub async fn verify_policy_signature(
        db: &DatabaseTransaction,
        signature_policy: &SignaturePolicy,
    ) -> Result<bool, PolicyError> {
        let crypto_impl = DefaultCryptoImpl;
        let data = signature_policy.encode_to_bytes();
        info!("verify_policy_data = {:?}", data);
        match crypto_impl
            .verify(Self::SIGNATURE_KEY_TYPE, Some(&signature_policy.key_version), data, signature_policy.signature.clone())
            .await
        {
            Ok(true) => Ok(true),
            Ok(false) => {
                PolicyRepository::set_is_corrupted(db, signature_policy.policy_id)
                    .await
                    .map_err(|e| PolicyError::DatabaseOperationError(e.to_string()))?;
                Ok(false)
            }
            Err(e) => {
                warn!("Failed to validate the policy signature taken out of the database: {:?}", e);
                Err(PolicyError::DatabasePolicySignatureError(e.to_string()))
            }
        }
    }
}


